var ScrambledEggs;
(function (ScrambledEggs) {
    var KeyState = (function () {
        function KeyState() {
            this._keysDown = {
            };
        }
        KeyState.prototype.KeyDown = function (keyCode) {
            this._keysDown[keyCode] = true;
        };
        KeyState.prototype.KeyUp = function (keyCode) {
            this._keysDown[keyCode] = false;
        };
        KeyState.prototype.KeyArrowLeft = function () {
            return this._keysDown[37] == true;
        };
        KeyState.prototype.KeyArrowUp = function () {
            return this._keysDown[38] == true;
        };
        KeyState.prototype.KeyArrowRight = function () {
            return this._keysDown[39] == true;
        };
        KeyState.prototype.KeyArrowDown = function () {
            return this._keysDown[40] == true;
        };
        return KeyState;
    })();
    ScrambledEggs.KeyState = KeyState;    
    var DrawLoop = (function () {
        function DrawLoop(updateFunction, targetFps) {
            if (typeof targetFps === "undefined") { targetFps = 60; }
            var drawables = [];
            for (var _i = 0; _i < (arguments.length - 2); _i++) {
                drawables[_i] = arguments[_i + 2];
            }
            this._frameCount = 0;
            this._updateCount = 0;
            this._targetFps = 60;
            this._actualFps = 60;
            this._actualUps = 60;
            this._enabled = false;
            var me = this;
            me._loopNumber = DrawLoop._loopCounter++;
            console.log("Creating DrawLoop " + me._loopNumber);
            me._updateFunc = updateFunction;
            var start = (new Date()).getTime();
            var mouse = {
                X: 0,
                Y: 0,
                Down: false,
                PreviouslyDown: false,
                PositionChanged: false
            };
            var keys = new KeyState();
            me._state = {
                Start: start,
                Time: function () {
                    return (new Date()).getTime() - start;
                },
                GetKeyState: function () {
                    return keys;
                },
                GetMouseState: function () {
                    return mouse;
                },
                GetActualFps: function () {
                    return me._actualFps;
                }
            };
            me._drawFunc = (function () {
                return typeof requestAnimationFrame === 'undefined' ? function () {
                    me.performDraw();
                } : function () {
                    requestAnimationFrame(function () {
                        me.performDraw();
                    });
                };
            })();
            setInterval(function () {
                me.performLoop();
            }, 1000);
            me.setFps(targetFps);
            me.setDrawables(drawables);
            me.enable();
            DrawLoop._undisposedLoopCounter++;
        }
        DrawLoop._loopCounter = 0;
        DrawLoop._alwaysPrint = false;
        DrawLoop._activeLoopCounter = 0;
        DrawLoop._undisposedLoopCounter = 0;
        DrawLoop.prototype.disable = function () {
            var me = this;
            console.log("Disabling DrawLoop " + me._loopNumber);
            if(me._enabled) {
                DrawLoop._activeLoopCounter--;
            }
            me._enabled = false;
            if(me._drawloop != null) {
                clearInterval(me._drawloop);
                me._drawloop = null;
            }
            if(me._updateloop) {
                clearInterval(me._updateloop);
                me._updateloop = null;
            }
            var ns = "drawloop" + me._loopNumber;
            $(document).off("mousemove." + ns + " touchmove." + ns);
            $(document).off("mousedown." + ns + " touchstart." + ns);
            $(document).off("mouseup." + ns + " touchend." + ns);
            $(document).off("keydown." + ns);
            $(document).off("keyup." + ns);
        };
        DrawLoop.prototype.dispose = function () {
            var me = this;
            console.log("Disposing DrawLoop " + me._loopNumber);
            me.disable();
            delete me._drawables;
            delete me._loopNumber;
            delete me._drawFunc;
            delete me._updateFunc;
            delete me._state;
            DrawLoop._undisposedLoopCounter--;
        };
        DrawLoop.prototype.enable = function () {
            var me = this;
            if(me._drawloop != null) {
                console.warn("cannot enable without disabling first");
                return;
            }
            console.log("Enabling DrawLoop " + me._loopNumber);
            me._enabled = true;
            me._drawloop = setInterval(me._drawFunc, 1000 / me._targetFps);
            me._updateloop = setInterval(function () {
                me._updateFunc(me._state);
            }, 1000 / me._targetFps / 2);
            var mouse = me._state.GetMouseState();
            var keys = me._state.GetKeyState();
            var ns = "drawloop" + me._loopNumber;
            $(document).on("mousemove." + ns + " touchmove." + ns, function (e) {
                mouse.X = e.pageX;
                mouse.Y = e.pageY;
                mouse.PositionChanged = true;
            });
            $(document).on("mousedown." + ns + " touchstart." + ns, function () {
                mouse.Down = true;
            });
            $(document).on("mouseup." + ns + " touchend." + ns, function () {
                mouse.Down = false;
            });
            $(document).on("keydown." + ns, function (e) {
                keys.KeyDown(e.which);
                e.preventDefault();
                return false;
            });
            $(document).on("keyup." + ns, function (e) {
                keys.KeyUp(e.which);
                e.preventDefault();
                return false;
            });
        };
        DrawLoop.prototype.performDraw = function () {
            var me = this;
            me._frameCount++;
            var time = me._state.Time();
            $.each(me._drawables, function () {
                var drawable = this;
                if(drawable.Draw != null) {
                    drawable.Draw(time);
                }
            });
        };
        DrawLoop.prototype.performUpdate = function () {
            var me = this;
            me._updateCount++;
            me._updateFunc(me._state);
            var mouseState = me._state.GetMouseState();
            mouseState.PreviouslyDown = mouseState.Down;
            mouseState.PositionChanged = false;
        };
        DrawLoop.prototype.getDefault = function (value, def) {
            return value == null ? value : def;
        };
        DrawLoop.prototype.setDrawables = function (drawables) {
            var me = this;
            me._drawables = [];
            if(drawables != null && drawables.length > 0) {
                $.each(drawables, function () {
                    me._drawables.push(this);
                });
                if(me._enabled) {
                    me.disable();
                    me.enable();
                }
            }
        };
        DrawLoop.prototype.setFps = function (targetFps) {
            var me = this;
            me._targetFps = me.getDefault(targetFps, 60);
            if(me._enabled) {
                me.disable();
                me.enable();
            }
        };
        DrawLoop.prototype.performLoop = function () {
            var me = this;
            if(!me._enabled) {
                return;
            }
            me._actualFps = me._frameCount;
            me._actualUps = me._updateCount;
            me._frameCount = 0;
            me._updateCount = 0;
            if((me._actualFps < me._targetFps * 0.9 || me._actualFps > me._targetFps * 1.1 || DrawLoop._alwaysPrint) && me._actualFps > 1) {
                console.warn("DrawLoop " + me._loopNumber + " | fps: " + me._actualFps + "/" + me._targetFps + " | ups: " + me._actualUps);
            }
        };
        return DrawLoop;
    })();
    ScrambledEggs.DrawLoop = DrawLoop;    
})(ScrambledEggs || (ScrambledEggs = {}));
